﻿using CanvasControl.Interface;
using CanvasControl.Model;
using CanvasControl.View;
using GraphDrawing.Graph.Model;
using GraphDrawing.Graph.View;
using Appearance = CanvasControl.View.Appearance;

namespace GraphDrawing.Graph.Behaviors
{
    public class GraphVisualizationBehavior : ICanvasBehavior
    {
        readonly ZOrderModel model;
        readonly IGraphObjectViewContainer viewContainer;

        CanvasEventsListener listener;
        ModelPainter painter;

        public Appearance SelectionBoxAppearance { get; private set; }
        public LineAppearance LinkingAppearance { get; private set; }
        public LineAppearance SelectedConnection { get; private set; }
        public LineAppearance DefaultConnection { get; private set; }

        public GraphVisualizationBehavior(ZOrderModel model, IGraphObjectViewContainer viewContainer)
        {
            this.model = model;
            this.viewContainer = viewContainer;
            SelectionBoxAppearance = new Appearance();
            LinkingAppearance = new LineAppearance();
            SelectedConnection = new LineAppearance();
            DefaultConnection = new LineAppearance();

            RegisterOwnedViews();
        }

        void ICanvasBehavior.Install(ICanvasView view, CanvasModel canvas)
        {
            var context = new ModelStateContext(model, canvas, view, viewContainer);
            canvas.AddPainter(PaintStages.CONTENT, painter = new ModelPainter(context));
            canvas.Subscribe(listener = new CanvasEventsListener(context));
        }

        void ICanvasBehavior.Uninstall(CanvasModel canvas)
        {
            canvas.Unsubscribe(listener);
            canvas.RemovePainter(painter);
        }

        /// <summary>
        /// Регистрирует в контейнере представления, необходимые при работе текущего поведения.
        /// </summary>
        void RegisterOwnedViews()
        {
            viewContainer.Add<ISelectionBoxView>(new SelectionBoxView(SelectionBoxAppearance));
            viewContainer.Add<ILinkingView>(new LinkingView(LinkingAppearance));
            viewContainer.Add(new ConnectionView(DefaultConnection, SelectedConnection));
        }

        class ModelPainter : IPainter
        {
            readonly ModelStateContext context;

            public ModelPainter(ModelStateContext context)
            {
                this.context = context;
            }

            public void Draw(DrawingContext dc)
            {
                var viewPort = context.CanvasModel.ViewPort;
                foreach (var block in context.ZOrder.EnumerateBlocks())
                {
                    var view = context.ViewContainer.GetView<BlockView>(block);
                    view.Draw(dc, viewPort, block);
                }
                var connectionView = context.ViewContainer.GetView<ConnectionView>();
                foreach (var connection in context.ZOrder.GetConnections())
                    connectionView.Draw(dc, viewPort, connection);
            }
        }
    }
}
